package com.tinem.platform.module.pojo.enums.security;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.Digester;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;

/**
 * @author fzh
 * @version v1
 * @program: platform
 * @className SignatureAlgorithm
 * @description 通过策略模式实现签名算法。
 * @site
 * @company
 * @create 2021-06-11 15:47
 */
@Slf4j
@AllArgsConstructor
public enum SignatureAlgorithm {

    /** sha256 + rsa算法签名 */
    SHA256_WITH_RSA((txt, signString) ->
            SecureUtil.sign(SignAlgorithm.SHA256withRSA).verify(txt.getBytes(StandardCharsets.UTF_8),HexUtil.decodeHex(signString))
            ,txt ->
            HexUtil.encodeHexStr(SecureUtil.sign(SignAlgorithm.SHA256withRSA).sign(txt.getBytes(StandardCharsets.UTF_8)))
    )
    /** sha512 算法签名 */
    ,SHA512((txt, signString) ->
            HexUtil.encodeHexStr(new Digester(DigestAlgorithm.SHA512).digest(txt.getBytes(StandardCharsets.UTF_8))).equals(signString)
            ,txt ->
            HexUtil.encodeHexStr(new Digester(DigestAlgorithm.SHA512).digest(txt.getBytes(StandardCharsets.UTF_8)))
    )
    /** sha512 + rsa算法签名 */
    ,SHA512_WITH_RSA((txt, signString) ->
            SecureUtil.sign(SignAlgorithm.SHA512withRSA).verify(txt.getBytes(StandardCharsets.UTF_8),signString.getBytes(StandardCharsets.UTF_8))
            ,txt ->
            HexUtil.encodeHexStr(SecureUtil.sign(SignAlgorithm.SHA512withRSA).sign(txt.getBytes(StandardCharsets.UTF_8)))
    )
    /** md2 + rsa算法签名 */
    ,MD2_WITH_RSA((txt, signString) ->
            SecureUtil.sign(SignAlgorithm.MD2withRSA).verify(txt.getBytes(StandardCharsets.UTF_8),signString.getBytes(StandardCharsets.UTF_8))
            ,txt ->
            HexUtil.encodeHexStr(SecureUtil.sign(SignAlgorithm.MD2withRSA).sign(txt.getBytes(StandardCharsets.UTF_8)))
    )
    /** md5 + rsa算法签名 */
    ,MD5_WITH_RSA((txt, signString) ->
            SecureUtil.sign(SignAlgorithm.MD5withRSA).verify(txt.getBytes(StandardCharsets.UTF_8),signString.getBytes(StandardCharsets.UTF_8))
            ,txt ->
            HexUtil.encodeHexStr(SecureUtil.sign(SignAlgorithm.MD5withRSA).sign(txt.getBytes(StandardCharsets.UTF_8)))
    )
    /** sha256 + ecdsa 算法签名 */
    ,SHA256_WITH_ECDSA((txt, signString) ->
            SecureUtil.sign(SignAlgorithm.SHA256withECDSA).verify(txt.getBytes(StandardCharsets.UTF_8),signString.getBytes(StandardCharsets.UTF_8))
            ,txt ->
            HexUtil.encodeHexStr(SecureUtil.sign(SignAlgorithm.SHA256withECDSA).sign(txt.getBytes(StandardCharsets.UTF_8)))
    )
    /** sha512 + ecdsa 算法签名 */
    ,SHA512_WITH_ECDSA((txt, signString) ->
        SecureUtil.sign(SignAlgorithm.SHA512withECDSA).verify(txt.getBytes(StandardCharsets.UTF_8),signString.getBytes(StandardCharsets.UTF_8))
    ,txt ->
            HexUtil.encodeHexStr(SecureUtil.sign(SignAlgorithm.SHA512withECDSA).sign(txt.getBytes(StandardCharsets.UTF_8)))
    )
    /** md5 算法签名 */
    ,MD5((txt, signString) -> {
        String sysSign = DigestUtil.md5Hex(txt);
        log.debug("txt:{}; sys sign:{}; user sign:{}",txt,sysSign,signString);
        return sysSign.equals(signString);
    } ,txt -> DigestUtil.md5Hex(txt))
    ;

    Verify signature;
    Sign sign;

    interface Verify{

        boolean verify(String txt,String signString);

    }
    interface Sign{
        String sign(String txt);
    }

    /**
     * 字符串签名
     * @param body 签名内容
     * @param key 盐
     * @return
     */
    public String sign(String body,String key, Long timestamp) {
        String txt = StrUtil.format("{}_{}_{}", body, key, timestamp);
        String singString = sign.sign(txt);
        log.debug("txt:{};sing:{}",txt,singString);
        return singString;
    }
    /**
     * 字符串签名
     * @param body 签名内容
     * @param key 盐
     * @return
     */
    public String sign(String body,String key, String timestamp,String apiRequestId) {
        String txt = StrUtil.format("{}_{}_{}", body, key, timestamp,apiRequestId);
        String singString = sign.sign(txt);
        log.debug("txt:{};sing:{}",txt,singString);
        return singString;
    }
    /**
     * 签名验证
     * @param body 字符串内容
     * @param key 盐
     * @param signString 签名字符串
     * @return 是否匹配
     */
    public boolean verify(String body, String key, Long timestamp,String apiRequestId, String signString){
        String txt = StrUtil.format("{}_{}_{}_{}",body,key,timestamp,apiRequestId);
        log.debug("txt:{};user signature:{}",txt,signString);
        return signature.verify(txt,signString);
    }
    /**
     * 签名验证
     * @param body 字符串内容
     * @param key 盐
     * @param signString 签名字符串
     * @return 是否匹配
     */
    public boolean verify(String body, String key, Long timestamp, String signString){
        String txt = StrUtil.format("{}_{}_{}",body,key,timestamp);
        log.debug("txt:{};user signature:{}",txt,signString);
        return signature.verify(txt,signString);
    }

    public static void main(String[] args) {
        String txt = "{\"merchOrderOriId\":\"105140_20211106114739596\",\"payUserEmail\":\"1209103220@qq.com\",\"payUserPhoneCountry\":\"+86\",\"payUserPhone\":\"17623423423\",\"description\":\"\\u8ba2\\u5355\\u63cf\\u8ff0\",\"timeExpire\":\"20211106114739\",\"orderType\":\"0\",\"ifsUrl\":\"http://www.baidu.com/ifsUrl\",\"merchOrderDate\":\"20211106114739\",\"priceCurrency\":\"usd\",\"priceAmount\":\"0.01\",\"ip\":\"127.0.0.1\",\"urlSync\":\"http://www.baidu.com/sync\",\"urlSuccBack\":\"http://www.baidu.com/success\",\"urlFailBack\":\"http://www.baidu.com/fail\",\"orderRemark\":\"\\u5145\\u503c\"}_1a2w3e_1636170459525";
        System.out.println(txt);
        System.out.println(DigestUtil.md5Hex(txt));
    }
}
